﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Documents;
using PSLib.CodeFormating.Lexems;
using PSLib.CodeFormating.Adapters;
using System.Windows.Media;
using System.Windows;
using System.ComponentModel;
using System.Windows.Input;

namespace LuaEditor2.UI.CodeEditor
{
	public class ColoringTextBox : RichTextBox
	{
		public ColoringTextBox()
		{
			editState = false;
		}

		protected override void OnTextChanged(TextChangedEventArgs e)
		{
			if (this.Document == null || editState) return;

			List<Paragraph> parList = new List<Paragraph>();
			foreach (var item in e.Changes)
			{
				TextPointer start = this.Document.ContentStart.GetPositionAtOffset(item.Offset);
				TextPointer end = this.Document.ContentStart.GetPositionAtOffset(item.Offset + item.AddedLength);
				parList.AddRange(this.Document.GetParagraphRange(start, end));
			}
			
			//Enumerate all editable blocks
			for (int i = 0; i < parList.Count; i++)
			{
				Paragraph paragraph = parList[i];
				//Validate changes by hash code
				TextRange textRange = new TextRange(paragraph.ElementStart, paragraph.ElementEnd);

				string blockText = textRange.Text;

				//Current block changed, parse it
				//Calculate block width and set FlowDocument page width
				int width = (int)paragraph.GetWidth() + 100;
				if (this.Document.PageWidth < width || Double.IsNaN(this.Document.PageWidth)) this.Document.PageWidth = width;

				//Remember last position
				int? lineCaretPos = null;
				TextPointer currentSelection = this.Selection.Start;
				if (currentSelection.Paragraph == paragraph)
				{
					lineCaretPos = (new TextRange(paragraph.ElementStart, currentSelection)).Text.Length;
				}

				//We will modify block in the changed event so suppres recurse
				editState = true;
				this.BeginChange();

				paragraph.LuaReFormat(this.Selection.Start,LanguageAdapter.LuaAdaptor, FormatLexem);

				this.EndChange();
				//Release recurse suppres
				editState = false;

				//Set new cursor position
				if (lineCaretPos.HasValue)
				{
					TextPointer newPosition = paragraph.ElementStart.GoToPoint(lineCaretPos.Value);
					this.Selection.Select(newPosition, newPosition);
				}
			}
			base.OnTextChanged(e);
		}

		protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
		{
			e.Handled = false;
			
			TextPointer ptSelectionStart = this.Selection.Start;
			if (e.Key == Key.Tab && Keyboard.Modifiers == ModifierKeys.None)
			{
				Paragraph paragraph = ptSelectionStart.Paragraph;
				string tabString = "    ";
				if (paragraph.Inlines.FirstInline == null) paragraph.Inlines.Add(new Run(tabString));
				else ptSelectionStart.InsertTextInRun(tabString);
				e.Handled = true;
			}

			if(!e.Handled)
			{
				base.OnPreviewKeyDown(e);
			}
		}

		private void FormatLexem(object sender, LuaEditor2.Extention.FormatLexemDelegateArgs e)
		{
			if (e.Inline == null) e.Inline = new Run(e.Lexem.LexemSource);
			e.Inline.Tag = e.Lexem;
			switch (e.Lexem.Type)
			{
				case LexemType.Operator:
					e.Inline.Foreground = new SolidColorBrush(Colors.Blue);
					break;
				case LexemType.String:
					e.Inline.Foreground = new SolidColorBrush(Colors.DarkRed);
					break;
				case LexemType.Comment:
					e.Inline.Foreground = new SolidColorBrush(Colors.Green);
					break;
				default:
					e.Inline.Foreground = new SolidColorBrush(Colors.Black);
					break;
			}
		}

		private bool editState;
	}
}
